package com.njcb.ams.support.security.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import com.njcb.ams.pojo.dto.standard.Response;
import com.njcb.ams.factory.domain.AppContext;
import com.njcb.ams.portal.SysBaseDefine;
import com.njcb.ams.factory.comm.WebGlobalInfo;
import com.njcb.ams.support.config.AmsConfigUtil;
import com.njcb.ams.support.security.bo.SecurityUser;
import com.njcb.ams.support.security.bo.SessionModel;
import com.njcb.ams.support.security.config.AmsSecurityConfiguration;
import com.njcb.ams.support.security.util.TokenUtil;
import com.njcb.ams.util.AmsAssert;
import com.njcb.ams.util.AmsDateUtils;
import com.njcb.ams.util.AmsJsonUtils;
import com.njcb.ams.util.AmsStringUtils;

import io.jsonwebtoken.Claims;

/**
 * 基于token认证，
 * @author LOONG
 */
public class TokenAuthFilter extends BasicAuthenticationFilter {
	private static final Logger logger = LoggerFactory.getLogger(TokenAuthFilter.class);

    public TokenAuthFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //从header 中提取token
        String token = request.getHeader("token");
		//允许所有人访问
        Boolean isPermitAll = false;
        FilterChainProxy fcp = (FilterChainProxy) AppContext.getBean("springSecurityFilterChain");
        if(null != fcp){
        	List<Filter> filterList = new ArrayList<Filter>();
            for (SecurityFilterChain filterChain : fcp.getFilterChains()) {
            	filterList.addAll(filterChain.getFilters());
    		}
            FilterSecurityInterceptor filterSecurityInterceptor = getFilter(FilterSecurityInterceptor.class, filterList);
            filterSecurityInterceptor.obtainSecurityMetadataSource();
            FilterInvocation fi = new FilterInvocation(request, response, chain);
            Collection<ConfigAttribute> attributes = filterSecurityInterceptor.obtainSecurityMetadataSource()
    				.getAttributes(fi);
            for (ConfigAttribute configAttribute : attributes) {
    			if("permitAll".equals(configAttribute.getAttribute())){
    				isPermitAll = true;
    			}
    		}
        }
        
        try {
        	AmsSecurityConfiguration securityConfig = AmsConfigUtil.getBean(AmsSecurityConfiguration.class);
            if (!isPermitAll && !AmsStringUtils.isEmpty(token) && SessionModel.TOKEN.equals(securityConfig.sessionModel())) {
            	Claims claims = TokenUtil.parseToken(token);
            	Map<String,Object> map = securityConfig.obtain(claims.getId());
            	AmsAssert.notNull(map,"token无效");
            	String username = (String) map.get("username");
            	AmsAssert.notNull(username,"存储的token中无有效的用户信息");
            	SecurityUser securityUser = securityConfig.loadUserByUsername(username, "", new HashMap<String,Object>(), false);
				WebGlobalInfo globalInfo = initWebGlobalInfo(securityUser);
				//交由GlobalInfoInterceptor统一处理
    			globalInfo.setSessionid(request.getSession().getId());
    			WebGlobalInfo.setGlobalInfo2HttpSession(request.getSession(), globalInfo);
            	UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(securityUser, "", securityUser.getAuthorities());
                //验证正常,生成authentication
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
            chain.doFilter(request, response);
        } catch (Exception e) {
        	e.printStackTrace();
        	logger.error(e.getMessage());
        	response.setCharacterEncoding("utf-8");
            response.setContentType("application/json;charset=utf-8");
            ServletOutputStream out = response.getOutputStream();
    		out.write(AmsJsonUtils.objectToJson(Response.buildFail("403", "token认证失败！" + e.getMessage())).getBytes("UTF-8"));
    		out.flush();
        }

    }

	static WebGlobalInfo initWebGlobalInfo(SecurityUser securityUser) {
		WebGlobalInfo globalInfo = new WebGlobalInfo();
		globalInfo.setUserId(securityUser.getId());
		globalInfo.setUserAttr(SysBaseDefine.USER_ATTR_REAL);
		globalInfo.setLoginName(securityUser.getLoginName());
		globalInfo.setUserName(securityUser.getUsername());
		globalInfo.setOrgNo(securityUser.getOrgnNo());
		globalInfo.setOrgName(securityUser.getOrgnName());
		globalInfo.setRoleCodes(securityUser.getRoleCodes());
		return globalInfo;
	}

	@SuppressWarnings({ "unchecked" })
	private <F extends Filter> F getFilter(Class<F> type, List<Filter> filters) {
		for (Filter f : filters) {
			if (type.isAssignableFrom(f.getClass())) {
				return (F) f;
			}
		}
		return null;
	}
}